﻿//-----------------------------------------------------------------------
// <copyright file="WorkItemPicker.cs" company="Microsoft Corporation">
//     Copyright (c) Microsoft Corporation 2011. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Internal.TeamFoundationServer.Submit
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;
    using System.Windows.Forms;
    using Microsoft.TeamFoundation.VersionControl.Client;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    using Properties;

    /// <summary>
    /// BugSelector class.
    /// </summary>
    internal partial class WorkItemPicker : WizardControlTemplate
    {
        /// <summary>
        /// Const string that all query name will start with.
        /// </summary>
        private const string QueryInit = "   ";

        /// <summary>
        /// WorkItemStore object.
        /// </summary>
        private WorkItemStore workItemStore;

        /// <summary>
        /// WorkItemCollection object.
        /// </summary>
        private WorkItemCollection workItemCollection;

        /// <summary>
        /// ChangeListPicker object.
        /// </summary>
        private ChangeListPicker changeListPicker;

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkItemPicker"/> class.
        /// </summary>
        public WorkItemPicker()
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.InitializeComponent();

                this.cmbTFSServer.Items.Add(Resources.NonWorkItemCheckinString);
                foreach (var item in TeamFoundationHelper.GetRegisteredCollectionNames())
                {
                    this.cmbTFSServer.Items.Add(item);
                }

                Utilities.FixComboItemsWidth(this, this.cmbTFSServer);

                if (this.cmbTFSServer.Items.Count > 0)
                {
                    Utilities.GetDefaultValue(this.cmbTFSServer, Settings.Default.TfsWorkItemServer);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Update window.
        /// </summary>
        /// <param name="title">Window Title.</param>
        /// <param name="description">Window Description.</param>
        /// <param name="backButtonEnabled">Back Button Enabled?</param>
        /// <param name="nextButtonEnabled">Next Button Enabled?</param>
        /// <param name="nextButtonCaption">Next Button Caption.</param>
        /// <param name="action">Action to perform on control.</param>
        public override void UpdateWindow(Label title, RichTextBox description, out bool backButtonEnabled, out bool nextButtonEnabled, out string nextButtonCaption, object action)
        {
            backButtonEnabled = true;
            nextButtonEnabled = true;
            nextButtonCaption = Resources.DefaultButtonNextCaption;

            title.Text = Resources.WorkItemPickerTitle;
            description.Text = Resources.WorkItemPickerDescription;
        }

        /// <summary>
        /// Next button event.
        /// </summary>
        public override void NextStep()
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                // Make sure to void current WorkItemCheckinInfo
                CheckinNotes.WorkItemsCheckinInfo = null;

                // If user select work item option, check if valid work items were selected.
                if (this.cmbTFSServer.Text != Resources.NonWorkItemCheckinString)
                {
                    bool containBug = this.gridBugs.Rows.Cast<DataGridViewRow>().Any(row => (bool)row.Cells[0].Value);

                    if (!containBug)
                    {
                        MessageBox.Show(
                            Resources.WorkItemNotSelectedErrorString,
                            Resources.ErrorString,
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error,
                            MessageBoxDefaultButton.Button1,
                            MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
                        return;
                    }
                }

                // On a future step checkinNotes class will need this info, we set it now, so we don't need to worry about retrieving it later.
                CheckinNotes.WorkItemsCheckinInfo = this.GetWorkItemInfos();

                Debug.Assert(this.changeListPicker == null || this.changeListPicker.IsDisposed, "BUGBUG changeListPicker should be null or not disposed at this point.");

                this.changeListPicker = new ChangeListPicker();
                this.FireOpenControl(this.changeListPicker);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Get Query FolderName based on the selected item of a combo box.
        /// </summary>
        /// <param name="comboBox">Combo box object.</param>
        /// <returns>Returns string containing folder name.</returns>
        private static string GetQueryFolderName(ToolStripComboBox comboBox)
        {
            for (int i = comboBox.SelectedIndex; i > -1; i--)
            {
                if (!comboBox.Items[i].ToString().StartsWith(QueryInit, StringComparison.OrdinalIgnoreCase))
                {
                    return comboBox.Items[i].ToString();
                }
            }

            return null;
        }

        /// <summary>
        /// Select TFS Collection.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void CmbTfsServerSelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.cmbTFSProject.Items.Clear();
                this.cmbTFSQuery.Items.Clear();
                this.gridBugs.Rows.Clear();

                if (this.cmbTFSServer.Text.Length == 0 || this.cmbTFSServer.Text == Resources.NonWorkItemCheckinString)
                {
                    return;
                }

                Utilities.SetDefaultValue("TfsWorkItemServer", this.cmbTFSServer.Text);

                // Retrieve WorkItemStore
                this.workItemStore = TeamFoundationHelper.GetWorkItemStore(this.cmbTFSServer.Text);

                if (this.workItemStore != null)
                {
                    // Get only project that user has read rights.
                    this.cmbTFSProject.Items.Clear();
                    foreach (var project in this.workItemStore.Projects.Cast<Project>().Where(project => project.HasWorkItemReadRightsRecursive))
                    {
                        this.cmbTFSProject.Items.Add(project.Name);
                    }

                    Utilities.FixComboItemsWidth(this, this.cmbTFSProject);
                }

                if (this.cmbTFSProject.Items.Count > 0)
                {
                    Utilities.GetDefaultValue(this.cmbTFSProject, Settings.Default.TfsWorkItemProject);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Select Project.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void CmbTfsProjectSelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.cmbTFSQuery.Items.Clear();
                this.gridBugs.Rows.Clear();

                if (this.cmbTFSProject.Text.Length == 0)
                {
                    return;
                }

                Utilities.SetDefaultValue("TfsWorkItemProject", this.cmbTFSProject.Text);

                if (this.workItemStore != null)
                {
                    // Based on Selected Project, list Query Folders.
                    QueryHierarchy queryHierarchy = this.workItemStore.Projects[this.cmbTFSProject.Text].QueryHierarchy;

                    foreach (QueryItem queryItem in queryHierarchy)
                    {
                        this.cmbTFSQuery.Items.Add(queryItem.Name);
                        this.AddQuery(null, queryItem as QueryFolder);
                    }

                    Utilities.FixComboItemsWidth(this, this.cmbTFSQuery);
                }

                if (this.cmbTFSQuery.Items.Count > 0)
                {
                    Utilities.GetDefaultValue(this.cmbTFSQuery, Settings.Default.TfsWorkItemQuery);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Select Query.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void CmbTfsQuerySelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.gridBugs.Rows.Clear();

                // Real queries start with 3 spaces, otherwise it is a query folder and we are not interested on that.
                if (this.cmbTFSQuery.Text.Length == 0 || !this.cmbTFSQuery.Text.StartsWith(QueryInit, StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }

                Utilities.SetDefaultValue("TfsWorkItemQuery", this.cmbTFSQuery.Text);

                try
                {
                    if (this.workItemStore != null)
                    {
                        var project = this.workItemStore.Projects[this.cmbTFSProject.Text];
                        if (project != null)
                        {
                            string queryFolderName = GetQueryFolderName(this.cmbTFSQuery);
                            if (string.IsNullOrEmpty(queryFolderName))
                            {
                                return;
                            }

                            var queryFolder = project.QueryHierarchy[queryFolderName] as QueryFolder;
                            if (queryFolder != null)
                            {
                                // Since Query starts with spaces, we need to remove it here.
                                string subQuery = this.cmbTFSQuery.Text.Substring(QueryInit.Length);

                                while (subQuery.Length > 0)
                                {
                                    if (subQuery.IndexOf("\\", StringComparison.OrdinalIgnoreCase) != -1 && queryFolder != null)
                                    {
                                        queryFolder = queryFolder[subQuery.Substring(0, subQuery.IndexOf("\\", StringComparison.OrdinalIgnoreCase))] as QueryFolder;
                                        subQuery = subQuery.Substring(subQuery.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }

                                // Retrieve the query definition here.
                                if (queryFolder != null)
                                {
                                    string queryText = ((QueryDefinition)queryFolder[subQuery]).QueryText;

                                    // Query may have some parameters.
                                    // for parameter like project we know how to solve it.
                                    queryText = queryText.Replace("@project", string.Format(CultureInfo.InvariantCulture, "'{0}'", this.cmbTFSProject.Text));

                                    try
                                    {
                                        // Retrieve list of WorkItem based on query.
                                        this.workItemCollection =
                                            this.workItemStore.Projects[this.cmbTFSProject.Text].Store.Query(queryText);
                                        foreach (WorkItem workItem in this.workItemCollection)
                                        {
                                            this.gridBugs.Rows.Add(false, workItem.Id, workItem.Title, workItem.State, workItem);

                                            // We are only interested in WorkItem that state is Active
                                            // Otherwise rows should be read only. -- The state is configurable in the app.config
                                            if (workItem.State != TfsSubmitConfig.ValidWorkItemState)
                                            {
                                                this.gridBugs.Rows[this.gridBugs.Rows.Count - 1].ReadOnly = true;
                                            }
                                        }
                                    }
                                    catch (ValidationException)
                                    {
                                        MessageBox.Show(
                                            Resources.WorkItemQueryErrorString,
                                            Resources.ErrorString,
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error,
                                            MessageBoxDefaultButton.Button1,
                                            MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (InvalidCastException)
                {
                    MessageBox.Show(
                        Resources.WorkItemQueryErrorString,
                        Resources.ErrorString,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error,
                        MessageBoxDefaultButton.Button1,
                        MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Add query items in combo box.
        /// </summary>
        /// <param name="path">Query Path.</param>
        /// <param name="queryFolder">QueryFolder object.</param>
        private void AddQuery(string path, IEnumerable<QueryItem> queryFolder)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                foreach (QueryItem queryItem in queryFolder)
                {
                    var subQueryFolder = queryItem as QueryFolder;
                    if (subQueryFolder != null)
                    {
                        string queryPath = string.Format(CultureInfo.InvariantCulture, "{0}{1}", (path == null ? null : path + "\\"), subQueryFolder.Name);
                        this.AddQuery(queryPath, subQueryFolder);
                    }
                    else
                    {
                        string queryName = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", QueryInit, (path == null ? null : path + "\\"), queryItem.Name);
                        this.cmbTFSQuery.Items.Add(queryName);
                    }
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Based on the list of Work Items selected, build a list.
        /// </summary>
        /// <returns>WorkItemCheckinInfo list.</returns>
        private WorkItemCheckinInfo[] GetWorkItemInfos()
        {
            var workItemCheckinInfo = new List<WorkItemCheckinInfo>();

            if (this.workItemCollection != null)
            {
                workItemCheckinInfo.AddRange(
                    from DataGridViewRow row in this.gridBugs.Rows
                    where (bool)row.Cells[0].Value
                    select
                    new WorkItemCheckinInfo(
                        row.Cells[4].Value as WorkItem,
                        WorkItemCheckinAction.Resolve));
            }

            return workItemCheckinInfo.ToArray();
        }
    }
}
